package cgl.narada.service.security.kmc;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import org.apache.log4j.Logger;

/**
 * A structure that maintains the current NTP timestamp and a sequence number
 * <br>
 * Created on Sep 14, 2005
 * 
 * @author Harshawardhan Gadgil (hgadgil@grids.ucs.indiana.edu)
 */
public class TimeStampedSeqNo {

    static Logger log = Logger.getLogger("TimeStampedSeqNo");
    
    private long _currentTimeStamp;
    private int _sequenceNumber;

    public TimeStampedSeqNo(long ts, int seq) {
        this._currentTimeStamp = ts;
        this._sequenceNumber = seq;
    }

    /**
     * @return Returns the _currentTimeStamp.
     */
    public long getTimeStamp() {
        return _currentTimeStamp;
    }

    /**
     * @return Returns the _sequenceNumber.
     */
    public int getSequenceNumber() {
        return _sequenceNumber;
    }

    /**
     * Checks of the specified TimeStampedSeqNo is greater than the current one
     * 
     * @param stssn
     * @return
     */
    public boolean isGreater(TimeStampedSeqNo prev) {

        // IF the NTP timestamp is > then stssn is clearly greater
        if (this._currentTimeStamp > prev._currentTimeStamp)
            return true;

        // IF a publisher publishes too fast like > 1000 times / sec then
        // probably
        // the NTP timestamps are same, in that case we check the sequence
        // numbers
        if (this._currentTimeStamp == prev._currentTimeStamp)
            if (this._sequenceNumber > prev._sequenceNumber)
                return true;

        // If we come here, then the specified stssn is going back in time

        System.out.println("TIMESTAMPSeqNo: {OLD}" + prev._currentTimeStamp
                + "::" + prev._sequenceNumber + "\t(NEW}" + _currentTimeStamp
                + "::" + _sequenceNumber);
        return false;
    }

    public String toString() {
        return _currentTimeStamp + "::" + _sequenceNumber;
    }

    public byte[] getBytes() {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        DataOutputStream dout = new DataOutputStream(bout);

        try {
            dout.writeLong(this._currentTimeStamp);
            dout.writeInt(this._sequenceNumber);

            dout.flush();
        } catch (IOException e) {
            log.error("Error marshalling SecureTimeStampedSeqNo: ", e);
        }

        return bout.toByteArray();
    }

    public static TimeStampedSeqNo unmarshal(byte[] bytes) {
        DataInputStream din = new DataInputStream(new ByteArrayInputStream(
                bytes));

        long ts;
        int seq;
        try {
            ts = din.readLong();
            seq = din.readInt();
        } catch (IOException e) {
            log.error("Error reading bytes", e);
            return null;
        }
        return new TimeStampedSeqNo(ts, seq);
    }
}
